#ifndef _SCRIPT_MGR_H
#define _SCRIPT_MGR_H

#define CALL_CREATURE_SCRIPT(a, b) if(a && a->m_script) a->m_script->b


enum Hooks
{
	ON_NEW_CHAR			= 0x00,
	ON_CHAR_DELETE		= 0x01,
	ON_ACCOUNT_LOGIN	= 0x02,
	ON_CHAR_LOGIN		= 0x03,
	ON_AREA_CHANGED		= 0x04,
	NUM_HOOKS,
};

typedef void (*on_new_char)(Player*);
typedef void (*on_char_login)(Player*);
typedef void (*on_area_changed)(ui32, Player*);
//////////////////////////////////////////////////////////////////////////
//	INFO for bool-Hooks
//	the return value of the boolean hooks is determined via logical AND
//	if any of the registered hooks returns false, it will automatically
//	be false for all.
typedef bool (*on_account_login)(const char*, const char*);

typedef void (*script_command)(const char*, Player*);

class GossipScript;
class GossipMenu;
class Player;
class Object;
class Creature;
class Unit;
class CreatureScript;

class DLL_EXPORT IEventReceiver
{
	friend class HookMgr;
protected:
	virtual void OnNewChar(Player* plr) {}
	virtual void OnCharDelete(Player* plr) {}
	virtual bool OnAccountLogin(const char* accname, const char* ip) { return true; }
	virtual void OnCharLogin(Player* plr) {}
	virtual void OnAreaChanged(ui32 areaid, Player* plr) {}
};

class DLL_EXPORT ScriptMgr : public Single<ScriptMgr>
{
	friend class World;
	void LoadScripts();
	map<char*, script_command> ChatCommands;	
	map<ui32, GossipScript*> m_cgossipscripts;
	map<ui32, CreatureScript* (*)(Creature*)> m_cscripts;
public:
	void register_hook(Hooks hook, void* functionptr);
	void register_hook(IEventReceiver* eventholder);
	void register_command(char* cmd, script_command proc);
	void register_creature_gossip(ui32 id, GossipScript* gs);
	void register_creature_script(ui32 id, CreatureScript* (*)(Creature*));
	template<class T>
	void register_luaclass();
	bool ParseCommand(char* cmd, char* args, Player* sender);

	GossipScript* GetScriptForCreature(ui32 id);
	CreatureScript* GetNewScriptForCreature(Creature* npc);
};

template<typename T>
void ScriptMgr::register_luaclass()
{
	LuaManager::getSingle()->RegisterLuaClass<T>();
}

class DLL_EXPORT HookMgr : public Single<HookMgr>
{
	friend class ScriptMgr;
	set<void*> HookList[NUM_HOOKS];
	set<IEventReceiver*> m_events;
public:
	void OnNewCharacter(Player*);
	void OnCharLogin(Player*);
	void OnAreaChanged(ui32, Player*);
	bool OnAccountLogin(const char*, const char*);
};

class DLL_EXPORT GossipMenuItem
{
	friend class GossipMenu;
	GossipMenuItem() : textbox(false) {}
	ui8 icon;
	ui32 id;
	char* text;
public:
	ui32 iid;
	ui32 clickprice;
	char* boxmessage;
	bool textbox;
};

class DLL_EXPORT GossipMenu
{
	ui32 textid;
	ui64 guid;
	set<GossipMenuItem*> m_items;
public:
	GossipMenu(ui32 textid, ui64 objectguid);
	GossipMenuItem* AddMenuItem(ui8 icon, char* text, ui32 id);
	GossipMenuItem* GetItem(ui32 id);
	void Send(Player* target);
};

class DLL_EXPORT GossipScript
{
public:
	virtual void GossipHello(Player* pSender, Object* pObject);
	virtual void GossipSelect(Player* pSender, Object* pObject, ui32 MenuId, char* code);
	virtual void OnRegister(Object* pReceiver);
};

class DLL_EXPORT CreatureScript
{
	Creature* m_creature;
public:
	CreatureScript(Creature* pCreature) : m_creature(pCreature)
	{
	}

	virtual void OnCombatStart(Unit* m_attacker)
	{
	}
};

#define sScriptMgr ScriptMgr::getSingle()
#define sHookMgr HookMgr::getSingle()

#endif